// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	11/5/2014 6:24:49 PM				
// -----------------------------

#include "LSystem.h"

LSystem::LSystem()
{
}

LSystem::~LSystem()
{
}

void LSystem::AddRule(const AString& input, const AString& output, UInt32 importance)
{
	for (UInt32 i = 0; i < importance; ++i)
		m_Rules.insert(make_pair(input, output));
}
AString	LSystem::Evaluate(const AString& input, UInt32 steps)
{
	// Evaluate the String
	AString output = input;
	do
	{
		output = EvaluateSingle(output);
		--steps;
	} 
	while (steps > 0);

	return output;
}

AString LSystem::EvaluateSingle(const AString& input)
{
	AStringStream output;
	AString innerInput = input;

	while (innerInput.length() > 0)
	{
		// Loop over the rules to see if one/more matches
		multimap<AString, AString> matchedRules;
		for (auto rulePair : m_Rules)
		{
			AString rule = rulePair.first;
			SizeT ruleLen = rule.length();
			AString sub = input.substr(0, ruleLen);
			// If the rule is a match
			// add it to the possibilities
			if (sub == rule)
				matchedRules.insert(rulePair);
		}

		// Make sure that we have possible rules
		// If not, just append the same character
		// and continue in the loop
		if (matchedRules.size() < 1)
		{
			output << innerInput[0];
			continue;
		}

		// Determine a random rule
		UInt32 ruleIdx = Math::Random(0, (Int32) matchedRules.size());
		auto ruleIt = matchedRules.begin();
		advance(ruleIt, ruleIdx);

		// Apply the Rule
		AString rule = (*ruleIt).first;
		AString ruleResult = (*ruleIt).second;
		output << ruleResult.c_str();

		// Remove the rule length
		// from the input string
		innerInput = innerInput.substr(rule.length(), innerInput.length() - rule.length());
	}

	// Return the result
	return output.str();
}